/*
    Name        :   Stephen Durfey
    Class       :   CS4080 - Operating System Concepts
    Instructor  :   Dr. Lee
    Due Date    :   02/10/2010
    Description :   This program tackles concepts in Interprocess Communication (IPC). The program
                    accepts a command line parameter that specifies how many prime numbers should be
                    found. The parent process populates an array with prime numbers. Once this array
                    has been populated, the parent uses the Linux system call, fork(), to spawn a child
                    process. The child process will go through the array of prime numbers and sum them up.
                    The child process will then print out its cpu usage, using the system call, getrusage().
                    The parent then takes over again, once the child terminates, prints out the child CPU
                    usage, and then its own CPU usage.
 
 
*/


#include <iostream>
#include <stdio.h>
#include <cmath>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <iomanip>
#include <sys/resource.h>

using namespace std;

void findPrimes(int primes[], int numPrimesToFind);
void sumPrimes(int primes[], int numPrimesToFind);

int main(int argc, char **argv)
{
    int numPrimesToFind = atoi(argv[1]);
    int primes[numPrimesToFind];
    struct rusage parent_usage;
    struct rusage child_usage;
    double usage = 0.0;
    pid_t childPID;
    pid_t child_pid;


    findPrimes(primes, numPrimesToFind);

    childPID = fork();

    if(childPID == -1)
    {
        cout << "No children were forked in the making of this program :(" << endl;
        exit(1);
    }

    //child process execution code
    if(childPID == 0)
    {
        cout << "=======================Child========================\n";
        sumPrimes(primes, numPrimesToFind);
        getrusage(RUSAGE_SELF, &child_usage); //gets CPU time for the process
        usage = (child_usage.ru_utime.tv_sec + child_usage.ru_stime.tv_sec) / pow(10.0, 6);
        cout << "Process ID: " << getpid() << " ..... " << " CPU time " << fixed << showpoint << setprecision(6) << usage << " s\n\n";
        cout << "Ending child process\n\n";
        cout << "====================================================\n\n";
    }
    else //parent process execution code
    {
    
        child_pid = wait(0);
    
        cout << "==========================Parent=========================\n\n";
        getrusage(RUSAGE_CHILDREN, &child_usage); // gets CPU usage for its child
        usage = (child_usage.ru_utime.tv_sec + child_usage.ru_stime.tv_sec) / pow(10.0, 6); 
        cout << "Child PID = "  << childPID << " Child CPU time = " << fixed << showpoint << setprecision(6) << usage << " s\n";
        getrusage(RUSAGE_SELF, &parent_usage);
        usage = (parent_usage.ru_utime.tv_sec + parent_usage.ru_stime.tv_sec) / pow(10.0, 6); 
        cout << "Parent PID = " << getpid() << " Parent CPU time = " << fixed << showpoint << setprecision(6) << usage << " s\n";
    
        cout << endl << endl << endl << "List of first " << numPrimesToFind << " prime numbers:\n";
    
        for(int index = 0; index < numPrimesToFind; index++)
        {
            cout << primes[index] << endl;
        }
    
        cout << "=============================================================\n\n";
        
    }

    return 0;
}

void findPrimes(int primes[], int numPrimesToFind)
{
    int divider = 2;
    int number = 2;
    int index = 0;
    int i = 0;
    bool prime = true;
    primes[0] = 2;

    /*loop through to find the first numPrimesToFind prime numbers*/
    while(index < numPrimesToFind)
    {
        
            /*A composite integer will have a prime number as a factor that does 
              not exceed the square root of the composite integer. If this prime
              is not found, then the number itself must be prime */
            
            while( primes[i] <= sqrt(number) && prime)
            {
                /*if number divides evenly into divider, then it is not prime*/
                if(number % primes[i] == 0)
                    prime = false;

                divider++;
                i++;
            }
                
            if(prime)
            {
                primes[index] = number;
                index++;
            }

            prime = true;
            divider = 2;
            number++;
            i = 0;
        
    }
}

void sumPrimes(int primes[], int numPrimesToFind)
{
    int sum = 0;

    for(int index = 0; index < numPrimesToFind; index++)
        sum += primes[index];

    cout << endl << "The sum of the first " << numPrimesToFind <<  " prime numbers is: " << sum << endl;
}

